package com.tools.common.io;

import com.tools.common.exception.IORuntimeException;
import com.tools.common.object.Note;
import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;

import java.io.*;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 *
 * */
@Note("获取 IO 流的工具类")
class IOStreamKit {

    IOStreamKit() {}

    @Note("默认读写缓冲区大小，单位是 byte 字节。这里默认是 10240 个字节，也就是 10 KB")
    public static final int DEFAULT_BUFFERED_BYTE_SIZE = 10240;

    @Note("NIO 两个 FileChannel 一次传输数据的上限，JDK 默认是 2GB")
    public static final long NIO_TRANS_LIMIT = 1024L * 1024 * 1024 * 2;


    /* *******************************************************************************************
     *
     *          InputStream 字节输入流
     *
     * *******************************************************************************************
     * */

    @Note("获取 URL 对象返回的网络字节输入流")
    public static InputStream urlInputStream(URL url) {
        try {
            return url.openConnection().getInputStream();
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }


    @Note("通过文件路径返回 FileInputStream 字节输入流")
    public static FileInputStream fileInputStream(String filePath) {
        String realPath = FileKit.getRealPath(filePath);
        try {
            return new FileInputStream(realPath);
        } catch (FileNotFoundException e) {
            String sourcePath = FileKit.getResourceFilePath(realPath);
            return fileInputStream(new File(sourcePath));
        }
    }


    @Note("通过文件路径返回 FileInputStream 字节输入流")
    public static FileInputStream fileInputStream(File file) {
        try {
            return new FileInputStream(file);
        } catch (FileNotFoundException e) {
            throw new IORuntimeException(e);
        }
    }


    @Note("通过文件实例获取 FileChannel 文件输入流的管道实例")
    public static FileChannel fileInputChannel(File file) {
        try (FileInputStream fileInput = new FileInputStream(file)) {
            return fileInput.getChannel();
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }


    @Note("通过文件路径获取 FileChannel 文件输入流的管道实例")
    public static FileChannel fileInputChannel(String filePath) {
        try (FileInputStream fileInput = new FileInputStream(filePath)) {
            return fileInput.getChannel();
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }


    @Note("使用字节输入流构建 BufferedInputStream 字节输入缓冲流")
    public static BufferedInputStream bufferedInputStream(InputStream input) {
        return new BufferedInputStream(input);
    }


    @Note("使用字节输入流构建 BufferedInputStream 指定缓冲区大小的字节输入缓冲流")
    public static BufferedInputStream bufferedInputStream(InputStream input, int buffSize) {
        if(buffSize <= 0) return new BufferedInputStream(input, DEFAULT_BUFFERED_BYTE_SIZE);
        return new BufferedInputStream(input, buffSize);
    }


    @Note("使用文件对象构建 BufferedInputStream 字节输入缓冲流")
    public static BufferedInputStream bufferedInputStream(File file) {
        FileInputStream fileInput = fileInputStream(file);
        return new BufferedInputStream(fileInput);
    }


    @Note("使用文件对象构建 BufferedInputStream 指定缓冲区大小的字节输入缓冲流")
    public static BufferedInputStream bufferedInputStream(File file, int buffSize) {
        FileInputStream fileInput = fileInputStream(file);
        if(buffSize <= 0) return new BufferedInputStream(fileInput, DEFAULT_BUFFERED_BYTE_SIZE);
        return new BufferedInputStream(fileInput, buffSize);
    }


    @Note("使用文件路径构建 BufferedInputStream 字节输入缓冲流")
    public static BufferedInputStream bufferedInputStream(String filePath) {
        FileInputStream fileInput = fileInputStream(filePath);
        return new BufferedInputStream(fileInput);
    }


    @Note("使用文件路径构建 BufferedInputStream 指定缓冲区大小的字节输入缓冲流")
    public static BufferedInputStream bufferedInputStream(String filePath, int buffSize) {
        FileInputStream fileInput = fileInputStream(filePath);
        if(buffSize <= 0) return new BufferedInputStream(fileInput, DEFAULT_BUFFERED_BYTE_SIZE);
        return new BufferedInputStream(fileInput, buffSize);
    }


    @Note("使用字节输入流构建 DataInputStream 数据字节输入流")
    public static DataInputStream dataInputStream(InputStream input) {
        return new DataInputStream(input);
    }


    @Note("使用文件对象构建 DataInputStream 数据字节输入缓冲流")
    public static DataInputStream dataInputStream(File file) {
        FileInputStream input = fileInputStream(file);
        return new DataInputStream(input);
    }


    @Note("使用文件路径构建 BufferedInputStream 数据字节输入缓冲流")
    public static DataInputStream dataInputStream(String filePath) {
        FileInputStream input = fileInputStream(filePath);
        return new DataInputStream(input);
    }


    @Note("使用字节输入流构建 ZipInputStream zip 压缩包字节输入流")
    public static ZipInputStream zipInputStream(InputStream input) {
        return (input instanceof ZipInputStream)
                ? (ZipInputStream) input
                : new ZipInputStream(input);
    }


    @Note("使用字节输入流构建字符集编码的 ZipInputStream zip 压缩包字节输入流")
    public static ZipInputStream zipInputStream(InputStream input, CharsetEnum charsetEnum) {
        return (input instanceof ZipInputStream)
                ? (ZipInputStream) input
                : new ZipInputStream(input, charsetEnum.getCharset());
    }


    @Note("使用文件对象构建 ZipInputStream zip 压缩包字节输入流")
    public static ZipInputStream zipInputStream(File file) {
        FileInputStream input = fileInputStream(file);
        return new ZipInputStream(input);
    }


    @Note("使用文件对象构建指定字符集编码的 ZipInputStream zip 压缩包字节输入流")
    public static ZipInputStream zipInputStream(File file, CharsetEnum charsetEnum) {
        FileInputStream input = fileInputStream(file);
        return new ZipInputStream(input, charsetEnum.getCharset());
    }


    @Note("使用文件路径构建 ZipInputStream zip 压缩包字节输入流")
    public static ZipInputStream zipInputStream(String filePath) {
        FileInputStream input = fileInputStream(filePath);
        return new ZipInputStream(input);
    }


    @Note("使用文件路径构建指定字符集编码的 ZipInputStream zip 压缩包字节输入流")
    public static ZipInputStream zipInputStream(String filePath, CharsetEnum charsetEnum) {
        FileInputStream input = fileInputStream(filePath);
        return new ZipInputStream(input, charsetEnum.getCharset());
    }


    @Note("用 buffer 构建 ByteArrayInputStream 字节输入流，然后读取数据放入 buffer 内返回")
    public static ByteArrayInputStream byteArrayInputStream(byte[] buffer) {
        if(buffer == null || buffer.length == 0) throw new IllegalArgumentException("字节缓冲数组不能为空");
        return new ByteArrayInputStream(buffer);
    }


    @Note("用 buffer 构建 ByteArrayInputStream 字节输入流，然后从 offset 开始读取 length 字节的数据放入 buffer 内返回")
    public static ByteArrayInputStream byteArrayInputStream(byte[] buffer, int offset, int length) {
        if(buffer == null || buffer.length == 0) throw new IllegalArgumentException("字节缓冲数组不能为空");
        if(offset < 0) throw new IllegalArgumentException("请输入正确的字节缓冲数组的开始读取的起始位置: " + offset);
        if(length <= 0) throw new IllegalArgumentException("请输入正确要读取字节缓冲数组的长度: " + length);
        if(offset >= length) throw new IllegalArgumentException("请输入正确要读取字节缓冲数组的 offset:" + offset
                + ", length:" + length);
        if(length > buffer.length) length = buffer.length;
        return new ByteArrayInputStream(buffer, offset, length);
    }


    /* ********************************************************************************************
     *
     *          OutputStream 字节输出流
     *
     * *********************************************************************************************
     * */


    @Note("通过文件路径返回 FileOutputStream 字节输出流，默认是覆盖输出")
    public static FileOutputStream fileOutputStream(String filePath) {
        return fileOutputStream(filePath, false);
    }


    @Note("通过文件路径返回 FileOutputStream 字节输出流，根据 append 决定是否是追加输出")
    public static FileOutputStream fileOutputStream(String filePath, boolean append) {
        String realPath = FileKit.getRealPath(filePath);
        try {
            return new FileOutputStream(realPath, append);
        } catch (FileNotFoundException e) {
            String sourcePath = FileKit.getResourceFilePath(realPath);
            return fileOutputStream(new File(sourcePath), append);
        }
    }


    @Note("通过文件实例返回 FileOutputStream 字节输出流，默认是覆盖输出")
    public static FileOutputStream fileOutputStream(File file) {
        return fileOutputStream(file, false);
    }


    @Note("通过文件实例返回 FileOutputStream 字节输出流，根据 append 决定是否是追加输出")
    public static FileOutputStream fileOutputStream(File file, boolean append) {
        try {
            return new FileOutputStream(file, append);
        } catch (FileNotFoundException e) {
            throw new IORuntimeException(e);
        }
    }


    @Note("通过文件路径返回用于输出的 FileChannel 文件输出流管道实例，默认是覆盖输出")
    public static FileChannel fileOutputChannel(String filePath) {
        return fileOutputChannel(filePath, false);
    }


    @Note("通过文件路径返回用于输出的 FileChannel 文件输出流管道实例，根据 append 决定是否是追加输出")
    public static FileChannel fileOutputChannel(String filePath, boolean append) {
        try (FileOutputStream fileOutput = new FileOutputStream(filePath, append)) {
            return fileOutput.getChannel();
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }


    @Note("通过文件路径返回用于输出的 FileChannel 文件输出流管道实例，默认是覆盖输出")
    public static FileChannel fileOutputChannel(File file) {
        return fileOutputChannel(file, false);
    }


    @Note("通过文件实例返回用于输出的 FileChannel 文件输出流管道实例，根据 append 决定是否是追加输出")
    public static FileChannel fileOutputChannel(File file, boolean append) {
        try (FileOutputStream fileOutput = new FileOutputStream(file, append)) {
            return fileOutput.getChannel();
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }


    @Note("使用字节输出流构建 BufferedOutputStream 字节输出缓冲流")
    public static BufferedOutputStream bufferedOutputStream(OutputStream output) {
        return new BufferedOutputStream(output, DEFAULT_BUFFERED_BYTE_SIZE);
    }


    @Note("使用字节输出流构建 BufferedOutputStream 指定缓冲区大小的字节输出缓冲流")
    public static BufferedOutputStream bufferedOutputStream(OutputStream output, int buffSize) {
        if(buffSize <= 0) return new BufferedOutputStream(output, DEFAULT_BUFFERED_BYTE_SIZE);
        return new BufferedOutputStream(output, buffSize);
    }



    @Note("使用文件对象构建 BufferedOutputStream 字节输出缓冲流，默认是覆盖输出")
    public static BufferedOutputStream bufferedOutputStream(File file) {
        FileOutputStream fileOutput = fileOutputStream(file);
        return new BufferedOutputStream(fileOutput, DEFAULT_BUFFERED_BYTE_SIZE);
    }


    @Note("使用文件对象构建 BufferedOutputStream 字节输出缓冲流，根据 append 决定是否是追加输出")
    public static BufferedOutputStream bufferedOutputStream(File file, boolean append) {
        FileOutputStream fileOutput = fileOutputStream(file, append);
        return new BufferedOutputStream(fileOutput, DEFAULT_BUFFERED_BYTE_SIZE);
    }


    @Note("使用文件对象构建 BufferedOutputStream 指定缓冲区大小的字节输出缓冲流")
    public static BufferedOutputStream bufferedOutputStream(File file, int buffSize) {
        FileOutputStream fileOutput = fileOutputStream(file);
        if(buffSize <= 0) return new BufferedOutputStream(fileOutput, DEFAULT_BUFFERED_BYTE_SIZE);
        return new BufferedOutputStream(fileOutput, buffSize);
    }


    @Note("使用文件对象构建 BufferedOutputStream 指定缓冲区大小的字节输出缓冲流，根据 append 决定是否是追加输出")
    public static BufferedOutputStream bufferedOutputStream(File file, int buffSize, boolean append) {
        FileOutputStream fileOutput = fileOutputStream(file, append);
        if(buffSize <= 0) return new BufferedOutputStream(fileOutput, DEFAULT_BUFFERED_BYTE_SIZE);
        return new BufferedOutputStream(fileOutput, buffSize);
    }


    @Note("使用文件路径构建 BufferedOutputStream 字节输出缓冲流")
    public static BufferedOutputStream bufferedOutputStream(String filePath) {
        FileOutputStream fileOutput = fileOutputStream(filePath);
        return new BufferedOutputStream(fileOutput, DEFAULT_BUFFERED_BYTE_SIZE);
    }


    @Note("使用文件路径构建 BufferedOutputStream 字节输出缓冲流，根据 append 决定是否是追加输出")
    public static BufferedOutputStream bufferedOutputStream(String filePath, boolean append) {
        FileOutputStream fileOutput = fileOutputStream(filePath, append);
        return new BufferedOutputStream(fileOutput, DEFAULT_BUFFERED_BYTE_SIZE);
    }


    @Note("使用文件路径构建 BufferedOutputStream 指定缓冲区大小的字节输出缓冲流")
    public static BufferedOutputStream bufferedOutputStream(String filePath, int buffSize) {
        FileOutputStream fileOutput = fileOutputStream(filePath);
        if(buffSize <= 0) return new BufferedOutputStream(fileOutput, DEFAULT_BUFFERED_BYTE_SIZE);
        return new BufferedOutputStream(fileOutput, buffSize);
    }


    @Note("使用文件路径构建 BufferedOutputStream 指定缓冲区大小的字节输出缓冲流，根据 append 决定是否是追加输出")
    public static BufferedOutputStream bufferedOutputStream(String filePath, int buffSize, boolean append) {
        FileOutputStream fileOutput = fileOutputStream(filePath, append);
        if(buffSize <= 0) return new BufferedOutputStream(fileOutput, DEFAULT_BUFFERED_BYTE_SIZE);
        return new BufferedOutputStream(fileOutput, buffSize);
    }


    @Note("使用字节输出流构建 DataOutputStream 数据字节输出流")
    public static DataOutputStream dataOutputStream(OutputStream output) {
        return new DataOutputStream(output);
    }


    @Note("使用文件实例构建 DataOutputStream 数据字节输出流")
    public static DataOutputStream dataOutputStream(File file) {
        FileOutputStream output = fileOutputStream(file);
        return new DataOutputStream(output);
    }


    @Note("使用文件实例构建 DataOutputStream 数据字节输出流，根据 append 决定该流是否是追加输出")
    public static DataOutputStream dataOutputStream(File file, boolean append) {
        FileOutputStream output = fileOutputStream(file, append);
        return new DataOutputStream(output);
    }


    @Note("使用文件路径构建 DataOutputStream 数据字节输出流")
    public static DataOutputStream dataOutputStream(String filePath) {
        FileOutputStream output = fileOutputStream(filePath);
        return new DataOutputStream(output);
    }


    @Note("使用文件路径构建 DataOutputStream 数据字节输出流，根据 append 决定该流是否是追加输出")
    public static DataOutputStream dataOutputStream(String filePath, boolean append) {
        FileOutputStream output = fileOutputStream(filePath, append);
        return new DataOutputStream(output);
    }



    @Note("根据 OutputStream 字节输出流获取 ZipOutputStream 输出流")
    public static ZipOutputStream zipOutputStream(OutputStream output) {
        return (output instanceof ZipOutputStream)
                ? (ZipOutputStream) output
                : new ZipOutputStream(output);
    }


    @Note("根据 OutputStream 字节输出流获取 ZipOutputStream 输出流，并指定字符集")
    public static ZipOutputStream zipOutputStream(OutputStream output, CharsetEnum charset) {
        if(charset == null) return zipOutputStream(output);
        return (output instanceof ZipOutputStream)
                ? (ZipOutputStream) output
                : new ZipOutputStream(output, charset.getCharset());
    }


    @Note("根据文件实例获取 ZipOutputStream 输出流")
    public static ZipOutputStream zipOutputStream(File file) {
        FileOutputStream fileOutput = fileOutputStream(file);
        return new ZipOutputStream(fileOutput);
    }


    @Note("根据文件实例获取 ZipOutputStream 输出流，根据 append 决定该流是否是追加输出")
    public static ZipOutputStream zipOutputStream(File file, boolean append) {
        FileOutputStream fileOutput = fileOutputStream(file, append);
        return new ZipOutputStream(fileOutput);
    }


    @Note("根据文件实例获取 ZipOutputStream 输出流，并指定字符集")
    public static ZipOutputStream zipOutputStream(File file, CharsetEnum charset) {
        FileOutputStream fileOutput = fileOutputStream(file);
        return new ZipOutputStream(fileOutput, charset.getCharset());
    }


    @Note("根据文件实例获取 ZipOutputStream 输出流，并指定字符集，并根据 append 决定该流是否是追加输出")
    public static ZipOutputStream zipOutputStream(File file, CharsetEnum charset, boolean append) {
        FileOutputStream fileOutput = fileOutputStream(file, append);
        return new ZipOutputStream(fileOutput, charset.getCharset());
    }


    @Note("根据文件路径获取 ZipOutputStream 输出流")
    public static ZipOutputStream zipOutputStream(String filePath) {
        FileOutputStream fileOutput = fileOutputStream(filePath);
        return new ZipOutputStream(fileOutput);
    }


    @Note("根据文件路径获取 ZipOutputStream 输出流，根据 append 决定该流是否是追加输出")
    public static ZipOutputStream zipOutputStream(String filePath, boolean append) {
        FileOutputStream fileOutput = fileOutputStream(filePath, append);
        return new ZipOutputStream(fileOutput);
    }


    @Note("根据文件路径获取 ZipOutputStream 输出流，并指定字符集")
    public static ZipOutputStream zipOutputStream(String filePath, CharsetEnum charset) {
        FileOutputStream fileOutput = fileOutputStream(filePath);
        return new ZipOutputStream(fileOutput, charset.getCharset());
    }


    @Note("根据文件路径获取 ZipOutputStream 输出流，并指定字符集，并根据 append 决定该流是否是追加输出")
    public static ZipOutputStream zipOutputStream(String filePath, CharsetEnum charset, boolean append) {
        FileOutputStream fileOutput = fileOutputStream(filePath, append);
        return new ZipOutputStream(fileOutput, charset.getCharset());
    }


    @Note("获取 ByteArrayOutputStream 流")
    public static ByteArrayOutputStream byteArrayOutputStream() {
        return new ByteArrayOutputStream();
    }


    @Note("获取 ByteArrayOutputStream 流，并指定缓冲区的大小，单位为字节。")
    public static ByteArrayOutputStream byteArrayOutputStream(int byteSize) {
        byteSize = (byteSize <= 0) ? DEFAULT_BUFFERED_BYTE_SIZE : byteSize;
        return new ByteArrayOutputStream(byteSize);
    }



    @Note("根据文件实例获取 7Z 压缩包的流实体")
    public static SevenZOutputFile sevenZOutputFile(File file) {
        try {
            return new SevenZOutputFile(file);
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }


    @Note("根据文件路径得到 7Z 压缩包的流实体")
    public static SevenZOutputFile sevenZOutputFile(String filePath) {
        try {
            return new SevenZOutputFile(new File(filePath));
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }

    @Note("根据 FileOutputStream 字节输出流获取 SevenZOutputFile 7Z 压缩包流实体")
    public static SevenZOutputFile sevenZOutputFile(FileOutputStream out) {
        try {
            return new SevenZOutputFile(out.getChannel());
        } catch (IOException e) {
            throw new IORuntimeException(e);
        } finally {
            close(out);
        }
    }

    /* *******************************************************************************************
     *
     *          Reader 字符输入流
     *
     * *******************************************************************************************
     * */


    @Note("根据 InputStream 字节输入流获取 InputStreamReader 字符输入流")
    public static InputStreamReader inputStreamReader(InputStream input) {
        return new InputStreamReader(input);
    }


    @Note("根据 InputStream 字节输入流获取 InputStreamReader 字符输入流，并指定字符集编码")
    public static InputStreamReader inputStreamReader(InputStream input, CharsetEnum charset) {
        if(charset == null) return inputStreamReader(input);
        return new InputStreamReader(input, charset.getCharset());
    }


    @Note("根据文件实例获取 InputStreamReader 字符输入流")
    public static InputStreamReader inputStreamReader(File file) {
        FileInputStream fileInput = fileInputStream(file);
        return new InputStreamReader(fileInput);
    }

    @Note("根据文件实例获取 InputStreamReader 字符输入流，并指定字符集编码")
    public static InputStreamReader inputStreamReader(File file, CharsetEnum charset) {
        FileInputStream fileInput = fileInputStream(file);
        return new InputStreamReader(fileInput, charset.getCharset());
    }

    @Note("根据文件路径获取 InputStreamReader 字符输入流")
    public static InputStreamReader inputStreamReader(String filePath) {
        FileInputStream fileInput = fileInputStream(filePath);
        return new InputStreamReader(fileInput);
    }


    @Note("根据文件路径获取 InputStreamReader 字符输入流，并指定字符集编码")
    public static InputStreamReader inputStreamReader(String filePath, CharsetEnum charset) {
        FileInputStream fileInput = fileInputStream(filePath);
        return new InputStreamReader(fileInput, charset.getCharset());
    }


    @Note("根据文件实例获取 FileReader 字符输入流")
    public static FileReader fileReader(File file) {
        try {
            return new FileReader(file);
        } catch (FileNotFoundException e) {
            throw new IORuntimeException(e);
        }
    }


    @Note("根据文件路径，获取 FileReader 字符输入流")
    public static FileReader fileReader(String filePath) {
        String realPath = FileKit.getRealPath(filePath);
        try {
            return new FileReader(realPath);
        } catch (FileNotFoundException e) {
            String sourcePath = FileKit.getResourceFilePath(realPath);
            return fileReader(new File(sourcePath));
        }
    }


    @Note("根据字符输入流，获取 BufferedReader 字符缓冲输入流")
    public static BufferedReader bufferedReader(Reader reader) {
        return new BufferedReader(reader, DEFAULT_BUFFERED_BYTE_SIZE);
    }


    @Note("根据字符输入流，获取 BufferedReader 字符缓冲输入流，其中缓冲区大小由 buffSize 指定，单位字节")
    public static BufferedReader bufferedReader(Reader reader, int buffSize) {
        if(buffSize <= 0) return new BufferedReader(reader, DEFAULT_BUFFERED_BYTE_SIZE);
        return new BufferedReader(reader, buffSize);
    }

    @Note("根据文件实例获取 BufferedReader 字符缓冲输入流")
    public static BufferedReader bufferedReader(File file) {
        FileReader reader = fileReader(file);
        return bufferedReader(reader);
    }

    @Note("根据文件实例获取 BufferedReader 字符缓冲输入流，其中缓冲区大小由 buffSize 指定，单位字节")
    public static BufferedReader bufferedReader(File file, int buffSize) {
        FileReader reader = fileReader(file);
        return bufferedReader(reader, buffSize);
    }


    @Note("根据文件路径获取 BufferedReader 字符缓冲输入流")
    public static BufferedReader bufferedReader(String filePath) {
        FileReader reader = fileReader(filePath);
        return bufferedReader(reader);
    }


    @Note("根据文件路径获取 BufferedReader 字符缓冲输入流，其中缓冲区大小由 buffSize 指定，单位字节")
    public static BufferedReader bufferedReader(String filePath, int buffSize) {
        FileReader reader = fileReader(filePath);
        return bufferedReader(reader, buffSize);
    }


    @Note("通过 InputStream 字节输入流获取 BufferedReader 字符缓冲输入流")
    public static BufferedReader bufferedReader(InputStream input) {
        return bufferedReader(inputStreamReader(input));
    }


    @Note("通过 InputStream 字节输入流获取 BufferedReader 字符缓冲输入流，并指定转换字符输入流的字符集")
    public static BufferedReader bufferedReader(InputStream input, CharsetEnum charset) {
        return bufferedReader(inputStreamReader(input, charset));
    }


    @Note("通过文件实例获取 BufferedReader 字符缓冲输入流，并指定转换字符输入流的字符集")
    public static BufferedReader bufferedReader(File file, CharsetEnum charset) {
        return bufferedReader(inputStreamReader(file, charset));
    }


    @Note("通过文件实例获取 BufferedReader 字符缓冲输入流，并指定转换字符输入流的字符集")
    public static BufferedReader bufferedReader(String filePath, CharsetEnum charset) {
        return bufferedReader(inputStreamReader(filePath, charset));
    }


    /* *******************************************************************************************
     *
     *          Writer 字符输出流
     *
     * *******************************************************************************************
     * */


    @Note("将 OutputStream 字节输出流转化为字符输出流 OutputStreamWriter")
    public static OutputStreamWriter outputStreamWriter(OutputStream output) {
        return new OutputStreamWriter(output);
    }


    @Note("将 OutputStream 字节输出流转化为指定字符集的字符输出流 OutputStreamWriter")
    public static OutputStreamWriter outputStreamWriter(OutputStream output, CharsetEnum charset) {
        return new OutputStreamWriter(output, charset.getCharset());
    }


    @Note("根据文件实例获取字符输出流 OutputStreamWriter")
    public static OutputStreamWriter outputStreamWriter(File file) {
        FileOutputStream output = fileOutputStream(file);
        return new OutputStreamWriter(output);
    }


    @Note("根据文件实例获取字符输出流 OutputStreamWriter，并指定其中的字符集")
    public static OutputStreamWriter outputStreamWriter(File file, CharsetEnum charset) {
        FileOutputStream output = fileOutputStream(file);
        return new OutputStreamWriter(output, charset.getCharset());
    }


    @Note("根据文件实例获取字符输出流 OutputStreamWriter，根据 append 判断该流是否是追加输出")
    public static OutputStreamWriter outputStreamWriter(File file, boolean append) {
        FileOutputStream output = fileOutputStream(file, append);
        return new OutputStreamWriter(output);
    }


    @Note("根据文件实例获取字符输出流 OutputStreamWriter，并指定其中的字符集。最后根据 append 判断该流是否是追加输出")
    public static OutputStreamWriter outputStreamWriter(File file, CharsetEnum charset, boolean append) {
        FileOutputStream output = fileOutputStream(file, append);
        return new OutputStreamWriter(output, charset.getCharset());
    }


    @Note("根据文件路径获取字符输出流 OutputStreamWriter")
    public static OutputStreamWriter outputStreamWriter(String filePath) {
        FileOutputStream output = fileOutputStream(filePath);
        return new OutputStreamWriter(output);
    }


    @Note("根据文件路径获取字符输出流 OutputStreamWriter，并指定其中的字符集")
    public static OutputStreamWriter outputStreamWriter(String filePath, CharsetEnum charset) {
        FileOutputStream output = fileOutputStream(filePath);
        return new OutputStreamWriter(output, charset.getCharset());
    }


    @Note("根据文件路径获取字符输出流 OutputStreamWriter，根据 append 判断该流是否是追加输出")
    public static OutputStreamWriter outputStreamWriter(String filePath, boolean append) {
        FileOutputStream output = fileOutputStream(filePath, append);
        return new OutputStreamWriter(output);
    }


    @Note("根据文件路径获取字符输出流 OutputStreamWriter，并指定其中的字符集。最后根据 append 判断该流是否是追加输出")
    public static OutputStreamWriter outputStreamWriter(String filePath, CharsetEnum charset, boolean append) {
        FileOutputStream output = fileOutputStream(filePath, append);
        return new OutputStreamWriter(output, charset.getCharset());
    }


    @Note("根据文件实例获取字符输出流 FileWriter")
    public static FileWriter fileWriter(File file) {
        return fileWriter(file, false);
    }


    @Note("根据文件实例获取字符输出流 FileWriter，根据 append 判断该流是否是追加输出")
    public static FileWriter fileWriter(File file, boolean append) {
        try {
            return new FileWriter(file, append);
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }


    @Note("根据文件路径获取字符输出流 FileWriter")
    public static FileWriter fileWriter(String filePath) {
        return fileWriter(filePath, false);
    }


    @Note("根据文件路径获取字符输出流 FileWriter，根据 append 判断该流是否是追加输出")
    public static FileWriter fileWriter(String filePath, boolean append) {
        String realPath = FileKit.getRealPath(filePath);
        try {
            return new FileWriter(realPath, append);
        } catch (IOException e) {
            String sourcePath = FileKit.getResourceFilePath(realPath);
            return fileWriter(new File(sourcePath), append);
        }
    }


    @Note("根据字符输出流获取 BufferedWriter 字符缓冲输出流")
    public static BufferedWriter bufferedWriter(Writer writer) {
        return new BufferedWriter(writer, DEFAULT_BUFFERED_BYTE_SIZE);
    }


    @Note("根据字符输出流获取 BufferedWriter 字符缓冲输出流，并指定缓冲区大小")
    public static BufferedWriter bufferedWriter(Writer writer, int buffSize) {
        if(buffSize <= 0) return new BufferedWriter(writer, DEFAULT_BUFFERED_BYTE_SIZE);
        return new BufferedWriter(writer, buffSize);
    }


    @Note("根据文件实例获取字符输出缓冲流")
    public static BufferedWriter bufferedWriter(File file) {
        FileWriter writer = fileWriter(file);
        return new BufferedWriter(writer, DEFAULT_BUFFERED_BYTE_SIZE);
    }


    @Note("根据文件实例获取字符输出缓冲流，并指定缓冲区大小")
    public static BufferedWriter bufferedWriter(File file, int buffSize) {
        FileWriter writer = fileWriter(file);
        return bufferedWriter(writer, buffSize);
    }


    @Note("根据文件实例获取字符输出缓冲流，根据 append 判断该流是否是追加输出")
    public static BufferedWriter bufferedWriter(File file, boolean append) {
        return bufferedWriter(file, DEFAULT_BUFFERED_BYTE_SIZE, append);
    }


    @Note("根据文件实例获取字符输出缓冲流，根据 append 判断该流是否是追加输出，并指定缓冲区大小")
    public static BufferedWriter bufferedWriter(File file, int buffSize, boolean append) {
        FileWriter writer = fileWriter(file, append);
        return bufferedWriter(writer, buffSize);
    }


    @Note("根据文件路径获取字符输出缓冲流")
    public static BufferedWriter bufferedWriter(String filePath) {
        FileWriter writer = fileWriter(filePath);
        return new BufferedWriter(writer, DEFAULT_BUFFERED_BYTE_SIZE);
    }


    @Note("根据文件路径获取字符输出缓冲流，并指定缓冲区大小")
    public static BufferedWriter bufferedWriter(String filePath, int buffSize) {
        FileWriter writer = fileWriter(filePath);
        return bufferedWriter(writer, buffSize);
    }


    @Note("根据文件路径获取字符输出缓冲流，根据 append 判断该流是否是追加输出")
    public static BufferedWriter bufferedWriter(String filePath, boolean append) {
        FileWriter writer = fileWriter(filePath, append);
        return bufferedWriter(writer, DEFAULT_BUFFERED_BYTE_SIZE);
    }


    @Note("根据文件路径获取字符输出缓冲流，根据 append 判断该流是否是追加输出，并指定缓冲区大小")
    public static BufferedWriter bufferedWriter(String filePath, int buffSize, boolean append) {
        FileWriter writer = fileWriter(filePath, append);
        return bufferedWriter(writer, buffSize);
    }


    @Note("根据字节输出流获取字符输出缓冲流")
    public static BufferedWriter bufferedWriter(OutputStream output) {
        OutputStreamWriter writer = outputStreamWriter(output);
        return bufferedWriter(writer);
    }


    @Note("根据字节输出流获取字符输出缓冲流，并指定缓冲区大小")
    public static BufferedWriter bufferedWriter(OutputStream output, int buffSize) {
        OutputStreamWriter writer = outputStreamWriter(output);
        return bufferedWriter(writer, buffSize);
    }

    /* *******************************************************************************************
     *
     *          关闭流操作
     *
     * *******************************************************************************************
     * */


    @Note("刷新字节输出流的输出")
    public static void flush(OutputStream output) {
        if(output != null) {
            try {
                output.flush();
            } catch (IOException e) {
                throw new IORuntimeException(e);
            }
        }
    }


    @Note("刷新字符输出流的输出")
    public static void flush(Writer writer) {
        if(writer != null) {
            try {
                writer.flush();
            } catch (IOException e) {
                throw new IORuntimeException(e);
            }
        }
    }


    @Note("结束 ZipOutputStream 压缩包字节输出流的写入")
    public static void finish(ZipOutputStream zos) {
        try {
            zos.finish();
        } catch (IOException e) {
            throw new IORuntimeException(e);
        } finally {
            close(zos);
        }
    }


    @Note("结束 SevenZOutputFile 7Z 压缩包流实体的写入")
    public static void finish(SevenZOutputFile out) {
        try {
            out.finish();
        } catch (IOException e) {
            throw new IORuntimeException(e);
        } finally {
            close(out);
        }
    }


    @Note("关闭 ZipInputStream 压缩包字节输入流前面打开的项")
    public static void closeEntry(ZipInputStream zis) {
        if(zis != null) {
            try {
                zis.closeEntry();
            } catch (IOException e) {
                throw new IORuntimeException(e);
            }
        }
    }

    @Note("关闭 ZipOutputStream 压缩包字节输出流前面打开的项")
    public static void closeEntry(ZipOutputStream zos) {
        if(zos != null) {
            try {
                zos.closeEntry();
            } catch (IOException e) {
                throw new IORuntimeException(e);
            }
        }
    }

    @Note("关闭可关闭的资源实例")
    public static void close(AutoCloseable closeable) {
        if(closeable != null) {
            try {
                closeable.close();
            } catch (Exception e) {
                throw new IORuntimeException(e);
            }
        }
    }

    @Note("缓冲流中读取一整行的操作，加了异常捕获")
    public static String readLine(BufferedReader reader) {
        try {
            return reader.readLine();
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }

    @Note("读取 ByteBuffer 内的所有字节数据，返回一个字节数组")
    public static byte[] readByteBuffer(ByteBuffer buffer) {
        if(buffer == null) return new byte[0];
        buffer.flip();
        byte[] data = buffer.array();
        buffer.clear();
        return data;
    }

    @Note("读取 ByteBuffer 内的所有字节数据，转为字符串返回")
    public static String readByteBufferToString(ByteBuffer buffer) {
        byte[] data = readByteBuffer(buffer);
        if(data.length == 0) return "";
        return new String(data);
    }

    @Note("使用移动指针的方式读取 ByteBuffer 内的所有字节数据，返回一个字节数组")
    public static byte[] readByteBufferMP(ByteBuffer buffer) {
        buffer.flip();
        int limit = buffer.limit();
        byte[] data = new byte[limit];
        for (int i = 0; i < limit; i++) {
            data[i] = buffer.get();
        }
        buffer.clear();
        return data;
    }

    @Note("使用移动指针的方式读取 ByteBuffer 内的所有字节数据，转为字符串返回")
    public static String readByteBufferMPToString(ByteBuffer buffer) {
        byte[] data = readByteBufferMP(buffer);
        if(data.length == 0) return "";
        return new String(data);
    }

    @Note("缓冲流中写入一整行的操作，外部加了异常捕获。写入过程自动写入换行和数据刷新")
    public static void writeLine(BufferedWriter writer, String data) {
        try {
            writer.write(data);
            writer.newLine();
            writer.flush();
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }


}
